/*	
	stencil - action script 3 isometric game engine.

	http://code.google.com/p/stencilas3/
	
	Copyright (c) 2010 Max Zhuravkov, All Rights Reserved.

	Permission is hereby granted, free of charge, to any person obtaining a copy of
	this software and associated documentation files (the "Software"), to deal in
	the Software without restriction, including without limitation the rights to
	use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
	of the Software, and to permit persons to whom the Software is furnished to do
	so, subject to the following conditions:

	The above copyright notice and this permission notice shall be included in all
	copies or substantial portions of the Software.

	THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
	IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
	FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
	AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
	LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
	OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
	SOFTWARE.
*/
package stencil.core.engine.scene.view 
{
	import adobe.utils.ProductManager;
	import flash.display.Sprite;
	import flash.display.DisplayObject;
	import flash.geom.Rectangle;
	import flash.geom.Point;
	import flash.media.Video;
	import flash.utils.Dictionary;
	import stencil.core.engine.IObjectFactory;
	import stencil.core.errors.NotImplementedMethodError;
	import stencil.core.errors.RequiredPropertyError;
	import stencil.core.engine.ISceneObject;
	import stencil.core.errors.ArgumentIsNullError;
	import stencil.core.engine.IMapArea;
	import stencil.core.engine.ITileSection;
	import stencil.core.engine.IGrid;
	import stencil.core.engine.display.ITileRenderer;
	import stencil.core.engine.display.IGraphicObject;
	import stencil.core.engine.display.IDisplayObject;
	import stencil.core.engine.display.IDisplayList;
	import stencil.core.engine.events.TileRenderEvent;
	import stencil.core.engine.events.TileDrawEvent;
	import stencil.core.engine.events.SceneUpdateEvent;
	import stencil.core.engine.events.VisibleAreaChangeEvent;
	import stencil.core.engine.scene.ISceneModel;
	import stencil.core.engine.scene.ISceneNode;
	import stencil.core.engine.scene.view.ISceneView;
	
	/**
	 * ...
	 * @author Max Zhuravkov
	 */
	public class AbstractSceneView extends Sprite implements ISceneView {
		
		private var _content:Sprite;
		
		private var _scene:ISceneModel
		
		private var _tileRenderer:ITileRenderer;
		
		private var _viewPort:Rectangle;
		
		private var _components:Dictionary = new Dictionary();
		
		private var _visibleArea:IMapArea;
		
		private var _displayPosition:Point = new Point();
		
		private var _displayFilter:IDisplayFilter;
		
		private var _displayObjectFactory:IObjectFactory;
		
		protected var flagSceneChanged:Boolean;
		
		protected var flagViewPortChanged:Boolean;
		
		protected var flagComponentsChanged:Boolean;
		
		protected var flagVisibleAreaChanged:Boolean;
		
		//------------------------------------------------------------------------------------------------
		// Constructor
		//------------------------------------------------------------------------------------------------
		
		public function AbstractSceneView() {
			this._content = new Sprite();
			
			this.addChild(this._content);
		}
		
		//------------------------------------------------------------------------------------------------
		// Public properties
		//------------------------------------------------------------------------------------------------
		
		/**
		 * @inheritDoc
		 */
		public function get content():DisplayObject {
			return this._content;
		}
		
		/**
		 * @inheritDoc
		 */
		public final function set displayObjectFactory(value:IObjectFactory):void {
			if (this._displayObjectFactory == value) {
				return;
			}
			
			if (this._displayObjectFactory) {
				this.displayObjectFactoryDetached(value);
			}
			this._displayObjectFactory = value;
			if (value) {
				this.displayObjectFactoryAttached(value);
			}
		}
		
		public final function get displayObjectFactory():IObjectFactory {
			return this._displayObjectFactory;
		}
		
		/**
		 * @inheritDoc
		 */
		public final function set scene(value:ISceneModel):void {
			if (this._scene == value) {
				return;
			}
			if (this._scene) {
				this.sceneRemoved(this._scene);
			}
			this._scene = value;
			if (this._scene) {
				this.sceneAdded(this._scene);
			}
			this.flagSceneChanged = true;
		}
		
		public final function get scene():ISceneModel {
			return this._scene;
		}
		
		/**
		 * @inheritDoc
		 */
		public function set tileRenderer(value:ITileRenderer):void {
			if (this._tileRenderer == value) {
				return;
			}
			if (this._tileRenderer) {
				this.tileRendererRemoved(this._tileRenderer);
			}
			this._tileRenderer = value;
			if (this._tileRenderer) {
				this.tileRendererAdded(this._tileRenderer);
			}
		}
		
		public function get tileRenderer():ITileRenderer {
			return this._tileRenderer;
		}
		
		/**
		 * @inheritDoc
		 */
		public function get componentNumber():int {
			return this._content.numChildren;
		}
		
		/**
		 * @inheritDoc
		 */
		public final function set viewPort(value:Rectangle):void {
			if (value == this._viewPort || (value && this._viewPort && this._viewPort.equals(value))) {
				return;
			}
			if (value) {
				if (!this._viewPort) {
					this._viewPort = new Rectangle();
				}
				
				this._viewPort.x = value.x;
				this._viewPort.y = value.y;
				this._viewPort.width = value.width;
				this._viewPort.height = value.height;
			}
			this.flagViewPortChanged = true;
		}
		
		/**
		 * @inheritDoc
		 */
		public final function get viewPort():Rectangle {
			return this._viewPort;
		}
		
		/**
		 * @inheritDoc
		 */
		public function get displayPosition():Point {
			return this._displayPosition;
		}
		
		/**
		 * @inheritDoc
		 */
		public final function set displayFilter(value:IDisplayFilter):void {
			if (this._displayFilter == value) {
				return;
			}
			this._displayFilter = value;
		}
		
		public final function get displayFilter():IDisplayFilter {
			return this._displayFilter;
		}
		
		//------------------------------------------------------------------------------------------------
		// Public methods
		//------------------------------------------------------------------------------------------------
		/**
		 * @inheritDoc
		 */
		public function addComponent(component:IGraphicObject):void {
			if (!component) {
				throw new ArgumentIsNullError("component");
			}
			var content:DisplayObject = component.content;
			this._content.addChild(content);
			this._components[content.name] = component;
		}
		
		/**
		 * @inheritDoc
		 */
		public function addComponentAt(component:IGraphicObject, index:int):void{
			if (!component) {
				throw new ArgumentIsNullError("component");
			}
			var content:DisplayObject = component.content;
			this._content.addChildAt(content, index);
			this._components[content.name] = component;
		}
		
		/**
		 * @inheritDoc
		 */
		public function removeComponent(component:IGraphicObject):void{
			if (!component) {
				throw new ArgumentIsNullError("component");
			}
			this._content.removeChild(component.content);
			delete this._components[content.name]
		}
		
		/**
		 * @inheritDoc
		 */
		public function removeComponentAt(index:int):void{
			var child:DisplayObject = this._content.removeChildAt(index);
			delete this._components[child.name]
		}
		
		/**
		 * @inheritDoc
		 */
		public function containsComponent(component:IGraphicObject):Boolean{
			if (!component) {
				throw new ArgumentIsNullError("component");
			}
			return this._content.contains(component.content);
		}
		
		/**
		 * @inheritDoc
		 */
		public function getComponentAt(index:int):IGraphicObject {
			var child:DisplayObject = this._content.getChildAt(index);
			
			return this._components[child.name];
		}
		
		/**
		 * @inheritDoc
		 */
		public function getComponentByName(name:String):IGraphicObject {
			var child:DisplayObject  = this._content.getChildByName(name);
			if (child == null) {
				return null;
			}
			return this._components[child.name];
		}
		
		/**
		 * @inheritDoc
		 */
		public final function displayAt(dx:Number, dy:Number):void {
			this._content.x = dx;
			this._content.y = dy;
			this._displayPosition.x = dx;
			this._displayPosition.y = dy;
		}
		
		/**
		 * @inheritDoc
		 */
		public final function render(viewPort:Rectangle, time:Number):void {
			
			try {
				
				this.renderScene(viewPort, time)
				
			}finally {
				this.flagComponentsChanged = false;
				this.flagVisibleAreaChanged = false;
				this.flagViewPortChanged = false;
			}
		}
		
		/**
		 * @inheritDoc
		 */
		public function dispose():void {
			
		}
		
		//------------------------------------------------------------------------------------------------
		// Protected properties
		//------------------------------------------------------------------------------------------------
		
		protected final function get container():Sprite {
			return this._content;
		}
		
		protected final function get components():Dictionary {
			return this._components;
		}
		
		//------------------------------------------------------------------------------------------------
		// Protected methods
		//------------------------------------------------------------------------------------------------
		
		protected function renderScene(view:Rectangle, time:Number):void {
			throw new NotImplementedMethodError("renderScene")
		}
		
		protected function sceneAdded(scene:ISceneModel):void {
			
		}
		
		protected function sceneRemoved(scene:ISceneModel):void {
			
		}
		
		protected function tileRendererAdded(tileRender:ITileRenderer):void {
			
		}
		
		protected function tileRendererRemoved(tileRender:ITileRenderer):void {
			
		}
		
		protected function displayObjectFactoryAttached(manager:IObjectFactory):void {
			
		}
		
		protected function displayObjectFactoryDetached(manager:IObjectFactory):void {
			
		}

	}

}